package com.yeban.bams.dao;

import com.yeban.bams.entity.Account;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @Desc TODO
 * @Author yeban
 * @Date 2025/10/28
 */
public class FileDao implements IDao<Account, List<Account>> {

    // 存储下一个ID的路径变量
    private static final String ID_FILE_PATH = "next_id.txt";
    // 存储所有ID的根文件夹
    private static final String ACCOUNTS_DIR_PATH = "accs";

    // 初始ID
    private Long ORIGINAL_ID = 100000000000000000L;
    // 当前ID
    private Long currentId;

    // 序列化：把账户对象写入文件
    private void serialize(Account acc) {
        // 1.如果文件夹不存在，创建账户文件夹
        File accsDir = new File(ACCOUNTS_DIR_PATH);
        if(!accsDir.exists()) {
            accsDir.mkdirs();
        }
        // 2.按照personId创建文件夹及命名
        File personIdDir = new File(accsDir, acc.getPersonId());
        if(!personIdDir.exists()) {
            personIdDir.mkdirs();
        }
        // 3.按照账户id创建文件及命名
        File accFile = new File(personIdDir,acc.getId() + ".txt");
        try(ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(accFile))) {
            oos.writeObject(acc);
            oos.flush();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    // 反序列化：从文件中读取账户对象
    private Account unSerialize(String personId, Long id) {
        // 1.判断：对应账户是否存在
        File file = new File(new File(ACCOUNTS_DIR_PATH, personId), id + ".txt");
        if(!file.exists()) {
            return null;
        }
        // 返回查找的对象
        try(ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file))) {
            return (Account) ois.readObject();
        } catch (IOException | ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 添加账户信息
     * @param acc
     * @return
     */
    @Override
    public boolean insert(Account acc) {
        serialize(acc);
        return true;
    }

    /**
     * 根据id和密码查询
     * @param id
     * @param pwd
     * @return
     * @throws IOException
     * @throws ClassNotFoundException
     */
    @Override
    public Account selectOne(Long id, String pwd) {
        // 判断：所有账户文件夹是否存在
        File accsDir = new File(ACCOUNTS_DIR_PATH);
        if(!accsDir.exists()) {
            return null;
        }
        // 遍历所有personId文件夹
        for(File personIdDir : accsDir.listFiles()) {
            // 如果对应的personId文件夹不为空
            if(personIdDir.isDirectory()) {
                // 匹配传入的id
                File accFile = new File(personIdDir, id + ".txt");
                // 如果账户文件存在
                if(accFile.exists()) {
                    Account acc = unSerialize(personIdDir.getName(), id);
                    if(acc != null && pwd.equals(acc.getPassword())) {
                        return acc;
                    }
                }
            }
        }
        return null;
    }

    @Override
    public Account selectOne(Long id) {
        File accsDir = new File(ACCOUNTS_DIR_PATH);
        if(!accsDir.exists()) {
            return null;
        }
        for(File personIdDir : accsDir.listFiles()) {
            if(personIdDir.isDirectory()) {
                File accFile = new File(personIdDir, id + ".txt");
                if(accFile.exists()) {
                    return unSerialize(personIdDir.getName(), id);
                }
            }
        }
        return null;
    }

    @Override
    public List<Account> selectAll() {
        List<Account> list = new ArrayList<Account>();
        File accsDir = new File(ACCOUNTS_DIR_PATH);
        if(!accsDir.exists()) {
            return list;
        }

        // 遍历accs所有账户的文件夹
        for(File personIdDir : accsDir.listFiles()) {
            // accs存在
            if(personIdDir.isDirectory()) {
                // 遍历personId所有账户的文件夹
                for(File accFile : personIdDir.listFiles()) {
                    // personId存在
                    if(accFile.exists()) {
                        Account acc = unSerialize(personIdDir.getName(), Long.parseLong(accFile.getName().replace(".txt","")));
                        if(acc != null) {
                            list.add(acc);
                        }
                    }
                }
            }
        }
        return list;
    }

    // 更新账户信息
    @Override
    public void update(Account acc) {
        serialize(acc);
    }

    // 获取账户id
    @Override
    public Long getId() {
        return currentId;
    }

    // 设置账户id
    @Override
    public void setId(Long id) {
        this.currentId = id;
    }

    /**
     * 生成账户ID
     * @return 开户时用的ID
     * @throws IOException
     */
    @Override
    public Long createID() {
        // 0. 判断文件是否存在
        File file = new File(ID_FILE_PATH);
        if(!file.exists()) {
            try {
                // 创建文件
                file.createNewFile();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            try( BufferedWriter bw = new BufferedWriter(new FileWriter(file)) ) {
                // 附上初始化ID
                bw.write(String.valueOf(ORIGINAL_ID));
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        // 声明id字符串
        String idStr;
        // 1.读取文件ID
        try( BufferedReader br = new BufferedReader(new FileReader(ID_FILE_PATH)) ){
            String line = br.readLine();
            if(line != null) {
                idStr = line;
            } else {
                idStr = String.valueOf(ORIGINAL_ID);    // 文件为空则使用初始ID
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        // 2.将ID存入当前对象
        setId(Long.parseLong(idStr) + 1);
        // 3.调用IDao中的方法生成当前可用ID和下一个可用ID
        currentId = IDao.super.createID();
        Long nextId = getId();
        // 4. 把下一个ID写回文件中（覆盖即可）
        try( BufferedWriter bw = new BufferedWriter(new FileWriter(ID_FILE_PATH,false)) ) {
            bw.write(String.valueOf(nextId));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return currentId;
    }
}
